package com.bigworld;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

import java.util.List;
import java.util.LinkedList;

import com.lb_stuff.mcmodify.minecraft.Chunk;
import com.lb_stuff.mcmodify.minecraft.FileRegion;
import com.lb_stuff.mcmodify.location.LocChunkInRegion;

public class MCWorld{
	int chunk_x,chunk_z;
	Mca chunk_now;
	public MCWorld(){
		chunk_now = null;
		chunk_x = chunk_z = 0;
	}
	public MCWorld(MCWorld mc){
		this.chunk_now = mc.chunk_now;
		this.chunk_x = mc.chunk_x;
		this.chunk_z = mc.chunk_z;
	}
	public String endWorld(){
		if(chunk_now==null)
			return "";
		else{
			String lst = chunk_now.toString();
			chunk_now.flush();
			chunk_now = null;
			System.gc();
			return lst;
		}
	}
	//世界坐标
	public short getBlock(int x, int y, int z){
		int l_x = (x<0)?((x+1)/16-1):x/16, l_z = (z<0)?((z+1)/16-1):z/16;
		if(l_x!=chunk_x || l_z!=chunk_z || chunk_now==null){//不是当前的chunk
			chunk_x = l_x; chunk_z = l_z;
			chunk_now = Mca.gMca(chunk_x, chunk_z);
		}
		if(y<0 || y>255)
			return -8848;
		return chunk_now.ch.BlockID(((x%16)+16)%16, y, ((z%16)+16)%16);
	}
	//世界坐标
	public MCWorld setBlock(int x, int y, int z, short blockid){
		int l_x = (x<0)?((x+1)/16-1):x/16, l_z = (z<0)?((z+1)/16-1):z/16;
		if(l_x!=chunk_x || l_z!=chunk_z || chunk_now==null){//不是当前的chunk
			chunk_x = l_x; chunk_z = l_z;
			chunk_now = Mca.gMca(chunk_x, chunk_z);
		}
		if(y<0 || y>255)
			return this;
		chunk_now.ch.BlockID(((x%16)+16)%16, y, ((z%16)+16)%16, blockid);
		return this;
	}
	//世界坐标
	public short getData(int x, int y, int z){
		int l_x = (x<0)?((x+1)/16-1):x/16, l_z = (z<0)?((z+1)/16-1):z/16;
		if(l_x!=chunk_x || l_z!=chunk_z || chunk_now==null){//不是当前的chunk
			chunk_x = l_x; chunk_z = l_z;
			chunk_now = Mca.gMca(chunk_x, chunk_z);
		}
		if(y<0 || y>255)
			return -8848;
		short value = chunk_now.ch.BlockData(((x%16)+16)%16, y, ((z%16)+16)%16);
		//确保返回的是正数
		return (short)((value+16)%16);
	}
	//世界坐标
	public MCWorld setData(int x, int y, int z, byte blockid){
		int l_x = (x<0)?((x+1)/16-1):x/16, l_z = (z<0)?((z+1)/16-1):z/16;
		if(l_x!=chunk_x || l_z!=chunk_z || chunk_now==null){//不是当前的chunk
			chunk_x = l_x; chunk_z = l_z;
			chunk_now = Mca.gMca(chunk_x, chunk_z);
		}
		if(y<0 || y>255)
			return this;
		chunk_now.ch.BlockData(((x%16)+16)%16, y, ((z%16)+16)%16, blockid);
		return this;
	}
	public MCWorld point(int x, int y, int z, int blockid){
		return this.setBlock(x, y, z, (short)blockid);
	} 
	public MCWorld contour(int x1, int y1, int z1, int x2, int y2, int z2){
		int v_x = x2-x1, v_y = y2-y1, v_z = z2-z1;
		int f_x = (v_x>=0)?1:-1, f_y = (v_y>=0)?1:-1 ,f_z = (v_z>=0)?1:-1;
		v_x = Math.abs(v_x); v_y = Math.abs(v_y); v_z = Math.abs(v_z); 
		int o_x=v_x, o_y=v_y, o_z=v_z;
		while(v_x+v_y+v_z != 0){
			float l1 = (o_x!=0)?(float)v_x/o_x:0;
			float l2 = (o_y!=0)?(float)v_y/o_y:0;
			float l3 = (o_z!=0)?(float)v_z/o_z:0;
			if(l1>l2)
				if(l1>l3)
					v_x--;
				else
					v_z--;
			else if(l2>l1)
					if(l2>l3)
						v_y--;
					else
						v_z--;
				else 
					if(l3>l1)
						v_z--;
					else
						v_x--;
			point(x1+f_x*v_x, y1+f_y*v_y, z1+f_z*v_z, 35);
			setData(x1+f_x*v_x, y1+f_y*v_y, z1+f_z*v_z, (byte)((y1+f_y*v_y)/16));
		}
		point(x1, y1, z1, 35);
		setData(x1, y1, z1, (byte)(y1/16));
		return this;
	} 
	public MCWorld line(int x1, int y1, int z1, int x2, int y2, int z2, int blockid){
		int v_x = x2-x1, v_y = y2-y1, v_z = z2-z1;
		int f_x = (v_x>=0)?1:-1, f_y = (v_y>=0)?1:-1 ,f_z = (v_z>=0)?1:-1;
		v_x = Math.abs(v_x); v_y = Math.abs(v_y); v_z = Math.abs(v_z); 
		int o_x=v_x, o_y=v_y, o_z=v_z;
		while(v_x+v_y+v_z != 0){
			float l1 = (o_x!=0)?(float)v_x/o_x:0;
			float l2 = (o_y!=0)?(float)v_y/o_y:0;
			float l3 = (o_z!=0)?(float)v_z/o_z:0;
			if(l1>l2)
				if(l1>l3)
					v_x--;
				else
					v_z--;
			else if(l2>l1)
					if(l2>l3)
						v_y--;
					else
						v_z--;
				else 
					if(l3>l1)
						v_z--;
					else
						v_x--;
			point(x1+f_x*v_x, y1+f_y*v_y, z1+f_z*v_z, blockid);
		}
		point(x1, y1, z1, blockid);
		return this;
	} 
	public MCWorld flat(int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3, int blockid){
		int v_x = x2-x1, v_y = y2-y1, v_z = z2-z1;
		int f_x = (v_x>=0)?1:-1, f_y = (v_y>=0)?1:-1 ,f_z = (v_z>=0)?1:-1;
		v_x = Math.abs(v_x); v_y = Math.abs(v_y); v_z = Math.abs(v_z); 
		int o_x=v_x, o_y=v_y, o_z=v_z;
		while(v_x+v_y+v_z != 0){
			float l1 = (o_x!=0)?(float)v_x/o_x:0;
			float l2 = (o_y!=0)?(float)v_y/o_y:0;
			float l3 = (o_z!=0)?(float)v_z/o_z:0;
			if(l1>l2)
				if(l1>l3)
					v_x--;
				else
					v_z--;
			else if(l2>l1)
					if(l2>l3)
						v_y--;
					else
						v_z--;
				else 
					if(l3>l1)
						v_z--;
					else
						v_x--;
			line(x1+f_x*v_x, y1+f_y*v_y, z1+f_z*v_z, x3, y3, z3, blockid);
		}
		line(x2, y2, z2, x3, y3, z3, blockid);
		return this;
	} 
}
class Mca{
	int x,z;
	public Chunk ch;
	Region re;
	static List<Mca> chunks;
	public static Mca gMca(int x, int z){
		if(chunks==null)
			chunks = new LinkedList<Mca>();
		for(Mca mi: chunks)
			if(mi.x==x && mi.z==z)
				return mi;
		return new Mca(x, z);
	}
	public Mca(int x, int z){
		this.x = x;
		this.z = z;
		this.ch = new Chunk(x, z);
		re = Region.gRegion(this.getRegionFile());
		chunks.add(this);
	}
	public void flush(){
		if(chunks==null)
			return;
		for(Mca mi: chunks)
			mi.toFile(mi);
		re.flush();
		chunks.clear();
	}
	public void toFile(Mca m){
		re.setChunk(m.ch);
	}
	public boolean equals(Object m){
		Mca mi = (Mca)m;
		if(mi.x==x && mi.z==z){
			mi.ch = ch;
			mi.re = re;
		}
		return false;
	}
	//返回chunk应该在的region文件
	public String getRegionFile(){
		return "r."+((x/32)-((x<0)?1:0))+"."+((z/32)-((z<0)?1:0))+".mca";
	}
	public String toString(){
		return re.toString();
	}
}
class Region{
	String regionname;
	public FileRegion region;
	static List<Region> regions;
	public static Region gRegion(String name){
		if(regions==null)
			regions = new LinkedList<Region>();
		for(Region r: regions)
			if(r.regionname.equals(name))
				return r;
		return new Region(name);
	}
	public Region(String name){
		regionname = name;
		try{
			region = new FileRegion(new File(name));
		}
		catch(IOException e){}
		if(regions==null)
			regions = new LinkedList<Region>();
		regions.add(this);
	}
	public void flush(){
		if(regions==null)
			return;
		regions.clear();
	}
	public void setChunk(Chunk c){
		try{
			this.region.setChunk(c.get_LocChunkInRegion(), c);
		}catch(IOException i){}
	}
	public String toString(){
		String allFile = "";
		for(Region r: regions){
			allFile += r.regionname+" ";
		}
		return allFile;
	}
}
